#include "main.h"
#include "lcd_spi_200.h" 

#include "sgl.h"
#include "sgl_draw_rect.h"
#include "sgl_draw_circle.h"
#include "sgl_draw_misc.h"
#include "sgl_draw_arc.h"


void SystemClock_Config(void);
void MPU_Config(void);

extern char *fbp;
int count = 0;
int x = 0, y = 0;
long int location = 0;
  
int main(void)
{
  MPU_Config();				
  SCB_EnableICache();		
  SCB_EnableDCache();		
  HAL_Init();				
  SystemClock_Config();	

  /* st7789v screen initialization320*240 */
  SPI_LCD_Init();

  
  x = 100; y = 100;       // Where we are going to put the pixel
  // Figure out where in memory to put the pixel
  uint16_t *ppp=(uint16_t *)fbp;
  for (y = 0; y < 320; y++)
  {
    for (x = 0; x < 240; x++) 
    {
      *ppp = 0xffff;
      ppp ++;
    }
  }
  /* The background is white */
  LCD_CopyBuffer(0,0,320,240, (uint16_t *)fbp);

  sgl_rect_t rect;
  rect.x1 = 20;
  rect.x2 = 300;
  rect.y1 = 50;
  rect.y2 = 60;

  sgl_rect_t rect2;
  rect2.x1 = 20;
  rect2.x2 = 30;
  rect2.y1 = 50;
  rect2.y2 = 60;

  /* Rectangle in red */
  sgl_draw_round_rect_solid(rect, 5, 0xff00, 0xffff); 
  sgl_draw_round_rect_solid(rect2, 5, 0xff, 0xffff);
  
  sgl_rect_t red;
  red.x1 = 120;
  red.x2 = 140;
  red.y1 = 120;
  red.y2 = 140;
  sgl_rect_t green;
  green.x1 = 140;
  green.x2 = 160;
  green.y1 = 140;
  green.y2 = 160;
  sgl_rect_t blue;
  blue.x1 = 160;
  blue.x2 = 180;
  blue.y1 = 160;
  blue.y2 = 180;
  sgl_draw_round_rect_solid(red, 5, 0x1f<<11, 0xffff);
  sgl_draw_round_rect_solid(green, 5, 0x3f<<5, 0xffff);
  sgl_draw_round_rect_solid(blue, 5, 0x1f, 0xffff);

  sgl_rect_t mix;
  mix.x1 = 0;
  mix.x2 = 80;
  mix.y1 = 160;
  mix.y2 = 180;

  sgl_draw_round_rect_solid(mix, 5, 31743, 0xffff);
  sgl_draw_circle_solid(250,170,60,0x1f, 0xffff);
  
  
  while (1)
  {
    if(rect2.x2 < 300) 
    {
      rect2.x1+=1;
      rect2.x2+=1;
      sgl_draw_round_rect_solid_rhalf(rect2, 5, 0xff, 0xff00);
    }
    else 
    {
      rect2.x1=20;
      rect2.x2=30;
      /* Rectangle in red */
      sgl_draw_round_rect_solid(rect, 5, 0xff00, 0xffff);
      sgl_draw_round_rect_solid(rect2, 5, 0xff, 0xffff);
      rect2.x1=25;
      rect2.x2=35;
    }


    /* Reduce refresh times and improve CPU usage */
    count ++;
    if (count % 8 == 0)
    {
      LCD_CopyBuffer(0,0,320,240, (uint16_t *)fbp);
    } 
  }
}


/****************************************************************************************************/
/**
  * @brief  System Clock Configuration
  *         The system Clock is configured as follow : 
  *            System Clock source            = PLL (HSE)
  *            SYSCLK(Hz)                     = 480000000 (CPU Clock)
  *            HCLK(Hz)                       = 240000000 (AXI and AHBs Clock)
  *            AHB Prescaler                  = 2
  *            D1 APB3 Prescaler              = 2 (APB3 Clock  120MHz)
  *            D2 APB1 Prescaler              = 2 (APB1 Clock  120MHz)
  *            D2 APB2 Prescaler              = 2 (APB2 Clock  120MHz)
  *            D3 APB4 Prescaler              = 2 (APB4 Clock  120MHz)
  *            HSE Frequency(Hz)              = 25000000
  *            PLL_M                          = 5
  *            PLL_N                          = 192
  *            PLL_P                          = 2
  *            PLL_Q                          = 4
  *            PLL_R                          = 2
  *            VDD(V)                         = 3.3
  *            Flash Latency(WS)              = 4
  * @param  None
  * @retval None
  */
  
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  
  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  __HAL_RCC_SYSCFG_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 5;
  RCC_OscInitStruct.PLL.PLLN = 192;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
  
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI5;
  PeriphClkInitStruct.Spi45ClockSelection = RCC_SPI45CLKSOURCE_D2PCLK1;	// SPI CLK = 120M
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }  
}


void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct;

  HAL_MPU_Disable();
  MPU_InitStruct.Enable 				= MPU_REGION_ENABLE;
  MPU_InitStruct.BaseAddress 		= 0x24000000;
  MPU_InitStruct.Size 					= MPU_REGION_SIZE_512KB;
  MPU_InitStruct.AccessPermission 	= MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.IsBufferable 		= MPU_ACCESS_BUFFERABLE;
  MPU_InitStruct.IsCacheable 		= MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsShareable 		= MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.Number 				= MPU_REGION_NUMBER0;
  MPU_InitStruct.TypeExtField 		= MPU_TEX_LEVEL0;
  MPU_InitStruct.SubRegionDisable 	= 0x00;
  MPU_InitStruct.DisableExec 		= MPU_INSTRUCTION_ACCESS_ENABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);	

  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}
